<!DOCTYPE html>
<meta charset="utf-8">
<html>
  <head>
    <title>Simple Tree Demo</title>
    <script src="d3.js"></script>
    <style>
    .nodelink {
      fill: none;
      stroke: #ccc;
      stroke-width: 4.5px;
    }
    .templink {
      fill: none;
      stroke: red;
      stroke-width: 3px;
    }
    </style>
</head>
<body> 
  <div id="viz"></div>
  <script type="text/javascript">
      var treeData = {"name" : "A", "children" : [ {"name" : "A1" },  {"name" : "A2" }, {"name" : "A3" } , {"name" : "b4"}] };
      var selectedNode = null;
      var draggingNode = null;

      // ------------- moving -------------------------------  
      var overCircle = function(d) {
        selectedNode = d;
        updateTempConnector();
      }
      var outCircle = function(d) {
        selectedNode = null;
        updateTempConnector();
      }

      var circleDragger = d3.behavior.drag()
        .on("dragstart", function(d){
          draggingNode = d;
          // it's important that we suppress the mouseover event on the node being dragged. Otherwise it will absorb the mouseover event and the underlying node will not detect it
          d3.select(this).attr( 'pointer-events', 'none' );
        })
        .on("drag", function(d) {
          d.x += d3.event.dx;
          d.y += d3.event.dy;
          var node = d3.select(this);
          node.attr( { cx: d.x, cy: d.y } );
          updateTempConnector();
        })
        .on("dragend", function(d){
          draggingNode = null;
          // now restore the mouseover event or we won't be able to drag a 2nd time
          d3.select(this).attr( 'pointer-events', '' );
        })

      var updateTempConnector = function() {
        var data = [];
        if ( draggingNode != null && selectedNode != null) {
          // have to flip the source coordinates since we did this for the existing connectors on the original tree
          data = [ {source: {x: selectedNode.y, y: selectedNode.x},
                    target: {x: draggingNode.x, y: draggingNode.y} } ];
        }
        var link = vis.selectAll(".templink").data(data);

        link.enter().append("path")
          .attr("class", "templink")
          .attr("d", d3.svg.diagonal() )
          .attr('pointer-events', 'none');

        link.attr("d", d3.svg.diagonal() )

        link.exit().remove();
      }

      // ------------- normal tree drawing code --------  
      var vis = d3.select("#viz").append("svg").attr("width", 400).attr("height", 300).append("svg:g").attr("transform", "translate(50, 0)")
      var tree = d3.layout.tree().size([200,200]);
      var nodes = tree.nodes(treeData);
      var links = tree.links(nodes);
  
      var diagonalHorizontal = d3.svg.diagonal().projection( function(d) { return [d.y, d.x]; } );
      var link = vis.selectAll(".nodelink")
        .data(links)
        .enter().append("path")
        .attr("class", "nodelink")
        .attr("d", diagonalHorizontal)
        .attr('pointer-events', 'none');
 
      var node = vis.selectAll("g.node")
        .data(nodes)
        .enter().append("g")
        .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
 
      node.append("circle")
        .attr("r", 5)
        .attr('pointer-events', 'none');

      // ------------- trickery to avoid collision detection

      // phantom node to give us mouseover in a radius around it
      node.append("circle")
        .attr("r", 60)
        .attr("opacity", 0.0) // change this to non-zero to see the target area
        .attr('pointer-events', 'mouseover')
        .on("mouseover", overCircle)
        .on("mouseout", outCircle)

      // a new, unconnected node that can be dragged near others to connect it
      newNodes = [ {x:300,y:5, name: 'new'} ];
      vis.selectAll(".lonely")
        .data(newNodes).enter().append("circle")
          .attr("r", 5)
          .attr("class", "lonely")
          .attr("cx", function(d) { return d.x; })
          .attr("cy", function(d) { return d.y; })
          .call(circleDragger)

    </script>
  </body>
</html>